// JSON差异对比算法
export interface DiffResult {
  path: string[];
  type: 'added' | 'removed' | 'modified' | 'moved' | 'unchanged';
  oldValue?: any;
  newValue?: any;
  oldIndex?: number;
  newIndex?: number;
}

export interface DiffStats {
  unchanged: number;
  modified: number;
  added: number;
  removed: number;
  moved: number;
}

// 深度比较两个值是否相等
function deepEqual(a: any, b: any): boolean {
  if (a === b) return true;
  
  if (a === null || b === null || a === undefined || b === undefined) {
    return a === b;
  }
  
  if (typeof a !== typeof b) return false;
  
  if (a instanceof Date && b instanceof Date) {
    return a.getTime() === b.getTime();
  }
  
  if (typeof a !== 'object') return false;
  
  if (Array.isArray(a) !== Array.isArray(b)) return false;
  
  if (Array.isArray(a)) {
    if (a.length !== b.length) return false;
    for (let i = 0; i < a.length; i++) {
      if (!deepEqual(a[i], b[i])) return false;
    }
    return true;
  }
  
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  
  if (keysA.length !== keysB.length) return false;
  
  for (const key of keysA) {
    if (!keysB.includes(key)) return false;
    if (!deepEqual(a[key], b[key])) return false;
  }
  
  return true;
}

// 获取值的类型字符串
function getValueType(value: any): string {
  if (value === null) return 'null';
  if (value === undefined) return 'undefined';
  if (Array.isArray(value)) return 'array';
  if (value instanceof Date) return 'date';
  return typeof value;
}

// 查找数组中移动的元素
function findMovedItems(oldArray: any[], newArray: any[]): Map<number, number> {
  const movedItems = new Map<number, number>();
  const usedNewIndices = new Set<number>();
  
  for (let oldIndex = 0; oldIndex < oldArray.length; oldIndex++) {
    const oldItem = oldArray[oldIndex];
    
    // 在新数组中查找相同的项
    for (let newIndex = 0; newIndex < newArray.length; newIndex++) {
      if (usedNewIndices.has(newIndex)) continue;
      
      if (deepEqual(oldItem, newArray[newIndex]) && oldIndex !== newIndex) {
        movedItems.set(oldIndex, newIndex);
        usedNewIndices.add(newIndex);
        break;
      }
    }
  }
  
  return movedItems;
}

// 主要的差异对比函数
export function compareJSON(oldObj: any, newObj: any, path: string[] = []): DiffResult[] {
  const results: DiffResult[] = [];
  
  // 如果两个值完全相等
  if (deepEqual(oldObj, newObj)) {
    results.push({
      path: [...path],
      type: 'unchanged',
      oldValue: oldObj,
      newValue: newObj
    });
    return results;
  }
  
  // 如果一个是null/undefined
  if (oldObj === null || oldObj === undefined || newObj === null || newObj === undefined) {
    // 修复：在对象属性上下文中，undefined <-> 其他值应该视为修改，而不是添加/删除
    // 只有在根级别或者确实是属性的添加/删除时才使用added/removed
    const isPropertyModification = path.length > 0; // 不是根级别的比较
    
    if (oldObj === undefined && newObj !== undefined) {
      results.push({
        path: [...path],
        type: isPropertyModification ? 'modified' : 'added',
        oldValue: oldObj,
        newValue: newObj
      });
    } else if (oldObj !== undefined && newObj === undefined) {
      results.push({
        path: [...path],
        type: isPropertyModification ? 'modified' : 'removed',
        oldValue: oldObj,
        newValue: newObj
      });
    } else {
      results.push({
        path: [...path],
        type: 'modified',
        oldValue: oldObj,
        newValue: newObj
      });
    }
    return results;
  }
  
  // 如果类型不同
  if (getValueType(oldObj) !== getValueType(newObj)) {
    results.push({
      path: [...path],
      type: 'modified',
      oldValue: oldObj,
      newValue: newObj
    });
    return results;
  }
  
  // 如果是基本类型且不相等
  if (typeof oldObj !== 'object' || oldObj instanceof Date) {
    results.push({
      path: [...path],
      type: 'modified',
      oldValue: oldObj,
      newValue: newObj
    });
    return results;
  }
  
  // 处理数组
  if (Array.isArray(oldObj) && Array.isArray(newObj)) {
    const maxLength = Math.max(oldObj.length, newObj.length);
    const movedItems = findMovedItems(oldObj, newObj);
    const processedOldIndices = new Set<number>();
    const processedNewIndices = new Set<number>();
    
    // 处理移动的项
    movedItems.forEach((newIndex, oldIndex) => {
      results.push({
        path: [...path, oldIndex.toString()],
        type: 'moved',
        oldValue: oldObj[oldIndex],
        newValue: newObj[newIndex],
        oldIndex,
        newIndex
      });
      processedOldIndices.add(oldIndex);
      processedNewIndices.add(newIndex);
    });
    
    // 处理其他项
    for (let i = 0; i < maxLength; i++) {
      if (processedOldIndices.has(i) || processedNewIndices.has(i)) continue;
      
      const oldValue = i < oldObj.length ? oldObj[i] : undefined;
      const newValue = i < newObj.length ? newObj[i] : undefined;
      
      if (oldValue === undefined && newValue !== undefined) {
        results.push({
          path: [...path, i.toString()],
          type: 'added',
          newValue: newValue
        });
      } else if (oldValue !== undefined && newValue === undefined) {
        results.push({
          path: [...path, i.toString()],
          type: 'removed',
          oldValue: oldValue
        });
      } else if (oldValue !== undefined && newValue !== undefined) {
        const subResults = compareJSON(oldValue, newValue, [...path, i.toString()]);
        results.push(...subResults);
      }
    }
    
    return results;
  }
  
  // 处理对象
  const oldKeys = Object.keys(oldObj);
  const newKeys = Object.keys(newObj);
  const allKeys = [...new Set([...oldKeys, ...newKeys])];
  
  for (const key of allKeys) {
    const hasOldKey = oldKeys.includes(key);
    const hasNewKey = newKeys.includes(key);
    
    if (!hasOldKey && hasNewKey) {
      // 新增的键
      results.push({
        path: [...path, key],
        type: 'added',
        newValue: newObj[key]
      });
    } else if (hasOldKey && !hasNewKey) {
      // 删除的键
      results.push({
        path: [...path, key],
        type: 'removed',
        oldValue: oldObj[key]
      });
    } else if (hasOldKey && hasNewKey) {
      // 可能修改的键
      const subResults = compareJSON(oldObj[key], newObj[key], [...path, key]);
      results.push(...subResults);
    }
  }
  
  return results;
}

// 计算差异统计
export function calculateStats(diffs: DiffResult[]): DiffStats {
  const stats: DiffStats = {
    unchanged: 0,
    modified: 0,
    added: 0,
    removed: 0,
    moved: 0
  };
  
  diffs.forEach(diff => {
    stats[diff.type]++;
  });
  
  return stats;
}

// 将路径转换为可读字符串
export function pathToString(path: string[]): string {
  if (path.length === 0) return 'root';
  
  return path.reduce((acc, segment, index) => {
    if (index === 0) return segment;
    
    // 如果是数组索引（纯数字）
    if (/^\d+$/.test(segment)) {
      return `${acc}[${segment}]`;
    }
    
    // 如果包含特殊字符，用引号包装
    if (/[^a-zA-Z0-9_$]/.test(segment)) {
      return `${acc}["${segment}"]`;
    }
    
    return `${acc}.${segment}`;
  });
}

// 格式化日期为中国习惯格式
function formatChineseDateTime(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');
  
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// 格式化值用于显示
export function formatValue(value: any): string {
  if (value === null) return 'null';
  if (value === undefined) return 'undefined';
  if (typeof value === 'string') return `"${value}"`;
  if (value instanceof Date) return formatChineseDateTime(value);
  if (typeof value === 'object') {
    return JSON.stringify(value, null, 2);
  }
  return String(value);
} 